﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TimeTracker.Provider;
using Utility;
using Utility.Configuration.Provider;

namespace TimeTracker
{
    public partial class Manager : Utility.Patterns.Singleton<Manager>
    {
        public IProject LastProject;
        public IProject CurrentProject;
        public ISession CurrentSession;

        private ProviderManager<System.Configuration.Provider.ProviderBase> providerManager;
        protected ProviderManager<System.Configuration.Provider.ProviderBase> ProviderManager
        {
            get
            {
                if (this.providerManager == null)
                {
                    this.providerManager = new ProviderManager<System.Configuration.Provider.ProviderBase>("logProviders");
                }

                return this.providerManager;
            }
        }

        private IProvider provider = null;
        protected IProvider Provider
        {
            get
            {
                string setProvider = Properties.Settings.Default["Provider"].ToString();

                if (this.provider != null) {
                    string currentProvider = this.ProviderManager.Provider.Name;

                    if (currentProvider != setProvider)
                    {
                        this.provider = null;
                    }
                }

                if (this.provider == null)
                {
                    this.provider = (IProvider)this.ProviderManager.Providers[setProvider];
                }

                return this.provider;
            }
        }

        public Manager()
        {

        }

        public IEnumerable<IProject> Projects
        {
            get { return this.Provider.GetProjects().Where(r => r.Project == null).OrderBy(r => r.Name); }
        }


        public IEnumerable<IProject> GetAllProjects()
        {
            IEnumerable<IProject> parentProjects = this.Projects;

            List<IProject> projects = new List<IProject>();

            projects.AddRange(parentProjects);

            foreach (IProject child in parentProjects)
            {
                projects.AddRange(child.AllProjects());
            }

            return projects;
        }

        public IEnumerable<IProject> GetProjectsForDay(DateTime day)
        {
            return this.Projects.Where(r => r.Duration(day).Ticks > 0);
        }

        public ISession AddSession(IProject project, DateTime startTime, DateTime? endTime)
        {
            return this.Provider.CreateSession(project, startTime, endTime);
        }

        public IProject GetProject(string strName)
        {
            return this.Projects.Where(r => r.Name == strName).FirstOrDefault();
        }

        public IProject GetProject(IProject parent, string name)
        {
            if (parent == null)
            {
                return this.GetProject(name);
            }
            return parent.Projects.Where(r => r.Name == name).FirstOrDefault();
        }

        public int GetSessionCount()
        {
            return this.Projects.Select(r => r.Sessions.ThatAreNotArchived().Count()).Sum();
        }

        public IEnumerable<DateTime> GetDaysBySession()
        {
            IEnumerable<ISession> sessions = GetSessions();

            IEnumerable<DateTime> days = sessions.Select(r => r.StartTime.ToDay()).Distinct();

            return days;
        }

        public IEnumerable<ISession> GetSessions()
        {
            return (from p in GetAllProjects() from s in p.Sessions.ThatAreNotArchived() select s);
        }

        public IProject StartTracking(string name)
        {
            return this.StartTracking(null, name);
        }

        public IProject StartTracking(IProject parent, string name)
        {
            IProject project = GetProject(parent, name);
            if (project == null)
            {
                project = this.Provider.CreateProject(parent, name);
                this.Provider.Save();
            }

            return this.StartTracking(project);
        }

        public IProject CreateProject(string name)
        {
            return this.CreateProject(null, name);
        }

        public IProject CreateProject(IProject parent, string name)
        {
            return this.Provider.CreateProject(parent, name);
        }

        public IProject StartTracking(IProject project)
        {
            CurrentSession = this.Provider.CreateSession(project, DateTime.Now, null);
            LastProject = CurrentProject;
            CurrentProject = project;

            this.Save();

            return CurrentProject;
        }

        public void StopTracking(DateTime endTime)
        {
            if ((CurrentProject == null) || (CurrentSession == null)) { return; }

            CurrentSession.EndTime = endTime;

            this.Save();

            LastProject = CurrentProject;
            CurrentProject = null;
            CurrentSession = null;
        }

        public void StopTracking()
        {
            this.StopTracking(DateTime.Now);
        }

        public IProject ResumeTrackingLastProject()
        {
            if (LastProject != null)
            {
                StartTracking(LastProject);

                CurrentProject = LastProject;
                LastProject = null;
            }

            return CurrentProject;
        }

        public void AddNote(string strText)
        {
            if (CurrentSession != null)
            {
                INote objNote = this.AddNote(CurrentSession, DateTime.Now, strText);
            }
        }

        public INote AddNote(ISession session, DateTime date, string text)
        {
            return this.Provider.CreateNote(session, date, text);
        }

        public void RemoveProject(IProject project)
        {
            this.Provider.RemoveProject(project);
            this.Provider.Save();
        }

        public void RemoveSession(ISession session)
        {
            this.Provider.RemoveSession(session);
            this.Provider.Save();
        }

        public void RemoveNote(INote note)
        {
            this.Provider.RemoveNote(note);
            this.Provider.Save();
        }

        public void Save()
        {
            this.Provider.Save();
        }

        #region Idle

        private DateTime idleTime = DateTime.MinValue;

        public void StartIdle()
        {
            this.idleTime = DateTime.Now;
        }

        public void EndIdle()
        {
            this.idleTime = DateTime.MinValue;
        }

        public DateTime IdleTime
        {
            get { return this.idleTime; }
        }

        public bool IsIdle()
        {
            return this.idleTime != DateTime.MinValue;
        }

        #endregion
    }
}
